package com.beiben.project.service.impl;

import com.beiben.common.GlobalConstant;
import com.beiben.project.domain.BeiBenTreeSelect;
import com.beiben.project.domain.Project;
import com.beiben.project.mapper.ProjectMapper;
import com.beiben.project.mapper.ProjectTeamMapper;
import com.beiben.project.service.IProjectService;
import com.beiben.system.file.domain.File;
import com.beiben.system.file.mapper.FileMapper;
import com.beiben.system.file.service.IFileService;
import com.beiben.utils.DateUtil;
import com.beiben.utils.SortComparator;
import com.beiben.work.process.domain.FileProcessUser;
import com.beiben.work.process.mapper.FileProcessUserMapper;
import com.beiben.work.process.service.IFileProcessUserService;
import com.beiben.workflow.domain.WfCheckLog;
import com.beiben.workflow.domain.WorkFlowConstant;
import com.beiben.workflow.mapper.WfCheckLogMapper;
import com.beiben.workflow.service.IWfApplyService;
import com.beiben.workflow.service.IWfCheckLogService;
import com.beiben.workflow.service.IWfCheckService;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.exception.BaseException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.ServletUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.framework.web.service.TokenService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 项目管理Service业务层处理
 *
 * @author 熊国强
 * @date 2020-12-03
 */
@Service
public class ProjectServiceImpl implements IProjectService {
    @Autowired
    private ProjectMapper projectMapper;

    @Autowired
    private TokenService tokenService;

    @Autowired
    private FileMapper fileMapper;

    @Autowired
    private IFileService fileService;

    @Autowired
    private ProjectTeamMapper projectTeamMapper;

    @Autowired
    private IFileProcessUserService fileProcessUserService;


    @Autowired
    private FileProcessUserMapper fileProcessUserMapper;

    @Autowired
    private IWfCheckLogService checkLogService;

    @Autowired
    private WfCheckLogMapper wfCheckLogMapper;


    @Autowired
    private IWfApplyService wfApplyService;

    @Autowired
    private IWfCheckService wfCheckService;



    /**
     * 查询项目管理
     *
     * @param projectId 项目管理ID
     * @return 项目管理
     */
    @Override
    public Project selectProjectById(Long projectId) {
//        System.out.println("返回数据：" + projectMapper.selectProjectById(projectId));
        return projectMapper.selectProjectById(projectId);
    }

    /**
     * 查询项目管理列表
     *
     * @param project 项目管理
     * @return 项目管理
     */
    @Override
    public List<Project> selectProjectList(Project project) {
        List<Project> projects = projectMapper.selectProjectList(project);
        return projects;
    }

    /**
     * 新增项目管理
     *
     * @param project 项目管理
     * @return 结果
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, timeout = 72000, rollbackFor = Exception.class)
    public int insertProject(Project project) {
        checkTime(project);
        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
        SysUser user = loginUser.getUser();
        project.setCreateBy(user.getUserName());
        project.setCreateTime(DateUtils.getNowDate());
        //判断是否为根项目管理
        boolean isRootProject = false;
        if (null == project.getParentId()) {
//            isRootProject = true;
            project.setParentId(0l);
            project.setAncestors("0");
        } else {
            Project pro = selectProjectById(project.getParentId());
            String ancestors = pro.getAncestors() + "," + pro.getProjectId();
            project.setAncestors(ancestors);
            Project ppt = projectMapper.selectProjectById(project.getParentId());
            project.setProjectCode(ppt.getProjectCode());
            project.setProjectType(ppt.getProjectType());
            if (DateUtil.getDateMinus(ppt.getStartTime(), project.getStartTime()) > 0 || DateUtil.getDateMinus(ppt.getFinishTime(), project.getFinishTime()) < 0) {
                throw new BaseException("子节点时间，任务时限超出项目时间范围。");
            }
        }
        int i = projectMapper.insertProject(project);
        // 非根项目（节点项目） 添加我的工作 - 待办工作 项目节点类工作 workType = 2;
        if (isRootProject) {
            FileProcessUser fileProcessUser = project.conversionToFileProcessUser();
            fileProcessUser.setWorkType("2");
            if (StringUtils.isNotNull(fileProcessUser.getFileId()) && StringUtils.isNotNull(fileProcessUser.getCheckUserId())) {
                fileProcessUserService.insertFileProcessUser(fileProcessUser);
            }
        }
        return i;
    }


    /**
     * 修改项目管理
     *
     * @param project 项目管理
     * @return 结果
     */
    @Override
    public int updateProject(Project project) {
        checkTime(project);
        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
        SysUser user = loginUser.getUser();
        project.setUpdateBy(user.getUserName());
        project.setUpdateTime(DateUtils.getNowDate());
        Project newParentProject = projectMapper.selectProjectById(project.getParentId());
        Project oldProject = projectMapper.selectProjectById(project.getProjectId());
        if (StringUtils.isNotNull(newParentProject) && StringUtils.isNotNull(oldProject)) {
            if (DateUtil.getDateMinus(newParentProject.getStartTime(), project.getStartTime()) > 0 || DateUtil.getDateMinus(newParentProject.getFinishTime(), project.getFinishTime()) < 0) {
                throw new BaseException("子节点时间，任务时限超出项目时间范围。");
            }
            String newAncestors = newParentProject.getAncestors() + "," + newParentProject.getProjectId();
            String oldAncestors = oldProject.getAncestors();
            project.setAncestors(newAncestors);
            updateProjectChildren(project.getProjectId(), newAncestors, oldAncestors, project);
        } else {
            checkChildTime(project);
        }
        // TODO: 2021-01-15 验证修改项目是否超时
        //重新计算是否超时
        if ("Y".equals(oldProject.getIsTimeOut())) {
            if(null!=oldProject.getRelFinishTime()){
                if (DateUtil.getDateMinus(oldProject.getRelFinishTime(), project.getFinishTime()) <= 0) {
                    project.setIsTimeOut("N");
                }
            }else{
                if (DateUtil.getDateMinus(DateUtil.getNowDate(), project.getFinishTime()) <= 0) {
                    project.setIsTimeOut("N");
                }
            }

        }
        return projectMapper.updateProject(project);
    }

    /**
     * 修改子元素关系
     *
     * @param projectId    被修改的项目ID
     * @param newAncestors 新的父ID集合
     * @param oldAncestors 旧的父ID集合
     */
    public void updateProjectChildren(Long projectId, String newAncestors, String oldAncestors, Project project) {
        List<Project> children = projectMapper.selectChildrenProjectById(projectId);
        for (Project child : children) {
            if (DateUtil.getDateMinus(child.getStartTime(), project.getStartTime()) < 0 || DateUtil.getDateMinus(child.getFinishTime(), project.getFinishTime()) > 0) {
                throw new BaseException("子节点时间，任务时限超出项目时间范围。");
            }
            child.setAncestors(child.getAncestors().replace(oldAncestors, newAncestors));
        }
        if (children.size() > 0) {
            projectMapper.updateProjectChildren(children);
        }
    }

    /*
     * 校验子节点时间是否有效
     * */
    public void checkChildTime(Project project) {
        List<Project> children = projectMapper.selectChildrenProjectById(project.getProjectId());
        for (Project child : children) {
            if (DateUtil.getDateMinus(child.getStartTime(), project.getStartTime()) < 0 || DateUtil.getDateMinus(child.getFinishTime(), project.getFinishTime()) > 0) {
                throw new BaseException("子节点时间，任务时限超出项目时间范围。");
            }
        }
    }

    /*
     * 校验时间是否符合规定
     * */
    public void checkTime(Project project) {
        if (null != project.getStartTime() && null != project.getFinishTime()) {
            project.setProjectTime(DateUtil.parseDateToStr(DateUtil.YYYY, project.getStartTime()));
            if (DateUtil.getDateMinus(project.getFinishTime(), project.getStartTime()) < 0) {
                throw new BaseException("开始时间不能大于结束时间。");
            }
        } else {
            throw new BaseException("开始时间和结束时间不能为空。");
        }
    }

    /**
     * 批量删除项目管理
     *
     * @param projectIds 需要删除的项目管理ID
     * @return 结果
     */
    @Override
    public int deleteProjectByIds(Long[] projectIds) {
        List<Project> projectList = projectMapper.selectProjectManagerIds(projectIds);
        for(Project p : projectList){
            if(0!=p.getState()){
                throw  new BaseException("节点已提交不能删除！");
            }
        }
        // TODO: 2020/12/9 删除子节点数据 
        for (Long projectId : projectIds) {
            List<Project> children = projectMapper.selectChildrenProjectById(projectId);
            for (Project child : children) {
                Long[] proids = new Long[]{child.getProjectId()};
                if(0!=child.getState()){
                    throw  new BaseException("节点已提交不能删除！");
                }
                List<FileProcessUser> fuList = fileProcessUserMapper.selectFileProcessUserByWorkIdsAndType(proids,GlobalConstant.PROJECT_WORK);
                for(FileProcessUser fu : fuList){
                   if(0!= fu.getState()){
                       throw  new BaseException("工作已提交不能删除！");
                   }
                }
                // TODO: 2020/12/9  删除子节点附件数据
                fileService.deleteFileByTableIds(GlobalConstant.PM_PROJECT, proids);
                // TODO: 2020/12/9  删除子节点关联分派任务数据
                fileProcessUserService.deleteFileProcessByWorkIds(proids);
                //删除子节点
                projectMapper.deleteProjectById(child.getProjectId());
            }
        }
        //todo 删除项目节点附件
        fileService.deleteFileByTableIds(GlobalConstant.PM_PROJECT, projectIds);
        // TODO: 2020/12/9 删除任务分派表
        fileProcessUserService.deleteFileProcessByWorkIds(projectIds);
        projectTeamMapper.deleteProjectTeamByProjectIds(projectIds);
        return projectMapper.deleteProjectByIds(projectIds);
    }

    /**
     * 删除项目管理信息
     *
     * @param projectId 项目管理ID
     * @return 结果
     */
    @Override
    public int deleteProjectById(Long projectId) {
        return projectMapper.deleteProjectById(projectId);
    }

    @Override
    public List<BeiBenTreeSelect> selectProjectTreeList(String relParentId) {
        Project project = new Project();
        project.setRelParentId(relParentId);
        List<Project> projects = projectMapper.selectProjectList(project);
        List<Project> projectTrees = buildProjectTree(projects);
        List<BeiBenTreeSelect> list = projectTrees.stream().map(BeiBenTreeSelect::new).collect(Collectors.toList());
        return list;
    }

    @Override
    public List<Project> selectProjectParentTreeList(String relParentId, String isParent) {
        List<Project> list = new ArrayList<>();
        if ("Y".equals(isParent)) {
            // 增加项目经理 2021-01-19 关联项目经理
            Project project = projectMapper.selectProjectById(Long.valueOf(relParentId));
            list.add(project);
        } else {
            List<Project> pList = projectMapper.selectProjectByParentId(Long.valueOf(relParentId));
            // TODO: 2021/1/8 查询工作表是否有工作
            FileProcessUser fileProcessUser = new FileProcessUser();
            fileProcessUser.setWorkId(Long.valueOf(relParentId));
            fileProcessUser.setWorkType(GlobalConstant.PROJECT_WORK);
            List<FileProcessUser> fList = fileProcessUserService.selectFileProcessUserPeerByWorkId(fileProcessUser);
            for (FileProcessUser f : fList) {
                Project p = new Project();
                p.setProjectId(f.getItemId());
                p.setParentId(f.getWorkId());
                p.setIsWork(1);
                p.setHasChildren(false);
                p.setTechnologyLeaderUserId(f.getCheckUserId());
                p.setTechnologyLeader(f.getCheckUserName());
                p.setStartTime(f.getStartTime());
                p.setFinishTime(f.getFinishTime());
                p.setRelFinishTime(f.getRealFinishTime());
                p.setProjectName(f.getWorkContent());
                p.setIsTimeOut(f.getIsTimeOut());
                p.setState(f.getState());
                p.setUserName(f.getUser().getNickName());
                //增加工时
                p.setFileHours(f.getFileHours());
                p.setSerial(f.getSerial());
                //增加项目经理
                p.setProjectManagerId(f.getProjectManagerId());
                list.add(p);
            }
            if (pList.size() > 0) {
                list.addAll(pList);
            }
        }
        if (list.size() > 0) {
//            list.sort(Comparator.comparing(Project::getSerial));
            TreeSet<Project> stringComparator = new TreeSet<>(new SortComparator());
            // 数据排序
            stringComparator.addAll(list);
            // 将排序完成的数据放回原集合
            list.clear();
            list.addAll(stringComparator);
        }
        return list;
    }

    @Override
    public List<File> selectFiles(Long projectId) {
        File file = new File();
        file.setTableId(projectId);
        file.setTableName(GlobalConstant.PM_PROJECT);
        return fileMapper.selectFileList(file);
    }


    @Override
    public int approveComplete(Long[] projectIds, Long[] itemIds) {
        if ((projectIds == null || projectIds.length == 0) && (itemIds == null || itemIds.length == 0)) {
            throw new RuntimeException("请选择要完成的项目！");
        }
        //当前用户
        Long currentUserId = SecurityUtils.getLoginUser().getUser().getUserId();
        int workNum = 0;
        // 项目工作
        if (itemIds != null && itemIds.length != 0) {
            //查询进行中的工作
            List<FileProcessUser> itemIdList = fileProcessUserMapper.selectProjectWorkManagerIds(itemIds);
            //工作完成
            workNum = this.approveCompleteWork(itemIdList, currentUserId);
            //是否完成节点 完成 触发节点审批
            Set<Long> workIdSet = new HashSet<>();
            for (FileProcessUser fileProcessUser : itemIdList) {
                Long workId = fileProcessUser.getWorkId();
                //已经判断过的不再判断
                if (workIdSet.contains(workId)) {
                    continue;
                }
                workIdSet.add(workId);
                //同级工作是否完成
                checkLogService.isTheProjectWorkCompleted(fileProcessUser.getItemId(), fileProcessUser.getCheckUserId());
            }
        }
        int projectNum = 0;
        //项目节点
        if (projectIds != null && projectIds.length != 0) {
            //查询项目节点
            List<Project> projectManagerIds = projectMapper.selectProjectManagerIds(projectIds);
            //节点完成
            projectNum = this.approveCompleteProject(projectManagerIds, projectIds, currentUserId);
            Set<Long> projectParentIdSet = new HashSet<>();
            for (Project project : projectManagerIds) {
                Long parentId = project.getParentId();
                //已经判断过的不再判断
                if (projectParentIdSet.contains(parentId)) {
                    continue;
                }
                projectParentIdSet.add(parentId);
                checkLogService.isTheProjectNodeCompleted(project.getProjectId(), project.getCheckUserId());
            }

        }
        return workNum + projectNum;
    }

    @Transactional(propagation = Propagation.REQUIRED, timeout = 72000, rollbackFor = Exception.class)
    int approveCompleteWork(List<FileProcessUser> itemIdList, Long currentUserId) {

        StringBuilder errorBuilder = new StringBuilder();
        //查询进行中的工作
        for (FileProcessUser fileProcessUser : itemIdList) {
            Long projectManagerId = fileProcessUser.getProjectManagerId();
            //校验 该projectId 的项目经理是否为 当前用户
            if (!projectManagerId.equals(currentUserId)) {
                errorBuilder.append(fileProcessUser.getWorkContent());
                errorBuilder.append("：无法完成！");
                errorBuilder.append("\n");
            }
        }
        if (StringUtils.isNotEmpty(errorBuilder.toString())) {
            throw new RuntimeException("完成失败：" + errorBuilder.toString());
        }
        int workNum = 0;
        Long[] itemIdArr = itemIdList.stream().map(FileProcessUser::getItemId).collect(Collectors.toList()).toArray(new Long[]{});
        if (itemIdArr.length > 0) {
            //修改项目工作状态
            workNum = fileProcessUserMapper.finishedFileProcessUserByIds(itemIdArr, DateUtils.getNowDate(), WorkFlowConstant.APPLY_STATE_PASS);
        }
        return workNum;
    }

    @Transactional(propagation = Propagation.REQUIRED, timeout = 72000, rollbackFor = Exception.class)
    int approveCompleteProject(List<Project> projectManagerIds, Long[] projectIds, Long currentUserId) {
        if (projectIds == null || projectIds.length == 0) {
            return 0;
        }
        //错误输出
        StringBuilder errorBuilder = new StringBuilder();
        for (Project project : projectManagerIds) {
            Long projectManagerId = project.getProjectManagerId();
            //校验 该projectId 的项目经理是否为 当前用户
            if (!projectManagerId.equals(currentUserId)) {
                errorBuilder.append(project.getProjectName());
                errorBuilder.append("的项目经理不是当前用户！");
                errorBuilder.append("\n");
            }
        }

        if (StringUtils.isNotEmpty(errorBuilder.toString())) {
            throw new RuntimeException("完成失败：" + errorBuilder.toString());
        }
        //查询节点下的自己的完成情况
        List<FileProcessUser> fileProcessUsers = fileProcessUserMapper.selectFileProcessUserByWorkIdsIsComplete(projectIds);
        if (fileProcessUsers.size() > 0) {
            errorBuilder.append("子任务存在未完成的任务,选中节点不可完成！");
            for (FileProcessUser fileProcessUser : fileProcessUsers) {
                errorBuilder.append(fileProcessUser.getWorkContent());
                errorBuilder.append("\n");
            }
        }
        if (StringUtils.isNotEmpty(errorBuilder.toString())) {
            throw new RuntimeException("完成失败：" + errorBuilder.toString());
        }
        for (Project project : projectManagerIds) {
            //查询是否存在 提交审核的 节点工作
            WfCheckLog wfCheckLog = wfCheckLogMapper.selectWfCheckByTableInfo(project.getProjectId(), GlobalConstant.PM_PROJECT);
            //存在 走审核通过 不存在 修改当前节点状态
            if (wfCheckLog != null) {
                //插入审批日志
                wfCheckLog.setCreateTime(DateUtils.getNowDate());
                wfCheckLog.setType(WorkFlowConstant.LOG_RECORD_TYPE_CHECK);
                int result = wfCheckLogMapper.insertWfCheckLog(wfCheckLog);

                //修改流程状态
                wfCheckService.updateWfCheckState(wfCheckLog);

                //修改申请状态
                wfApplyService.updateApplyState(wfCheckLog.getApplyId(), WorkFlowConstant.APPLY_STATE_PASS);
            }
        }
        //修改项目节点状态
        return projectMapper.finishedFileProcessUserByIds(projectIds, DateUtils.getNowDate(), WorkFlowConstant.APPLY_STATE_PASS);
    }

    /**
     * 构建前端所需要树结构
     *
     * @param projects 项目列表
     * @return 树结构列表
     */
    public List<Project> buildProjectTree(List<Project> projects) {
        List<Project> returnList = new ArrayList<Project>();
        List<Long> tempList = new ArrayList<Long>();
        for (Project project : projects) {
            tempList.add(project.getProjectId());
        }
        for (Iterator<Project> iterator = projects.iterator(); iterator.hasNext(); ) {
            Project pt = (Project) iterator.next();
            // 如果是顶级节点, 遍历该父节点的所有子节点
            if (!tempList.contains(pt.getParentId())) {
                recursionFn(projects, pt);
                returnList.add(pt);
            }
        }
        if (returnList.isEmpty()) {
            returnList = projects;
        }
        return returnList;
    }


    /**
     * 递归列表
     */
    private void recursionFn(List<Project> list, Project t) {
        // 得到子节点列表
        List<Project> childList = getChildList(list, t);
        t.setChildren(childList);
        for (Project tChild : childList) {
            if (hasChild(list, tChild)) {
                recursionFn(list, tChild);
            }
        }
    }

    /**
     * 得到子节点列表
     */
    private List<Project> getChildList(List<Project> list, Project t) {
        List<Project> tlist = new ArrayList<Project>();
        Iterator<Project> it = list.iterator();
        while (it.hasNext()) {
            Project n = (Project) it.next();
            if (StringUtils.isNotNull(n.getParentId()) && n.getParentId().longValue() == t.getProjectId().longValue()) {
                tlist.add(n);

            }
        }
        return tlist;
    }

    /**
     * 判断是否有子节点
     */
    private boolean hasChild(List<Project> list, Project t) {
        return getChildList(list, t).size() > 0 ? true : false;
    }

    /**
     * 定时任务判断项目是否超时
     */
    public void timeoutVerification() {
        //获取所有项目信息
        Project project = new Project();
        project.setIsTimeOut("N");
        List<Project> projects = projectMapper.selectProjectList(project);
        this.checkProcessUserTimeOut(projects);
    }

    /**
     * 判断项目是否超时
     *
     * @param projects
     */
    private void checkProcessUserTimeOut(List<Project> projects) {
        // 超时子任务 ItemId 集合
        List<Long> timeOutFIleProcessUserIds = new ArrayList<>();
        // 循环子任务
        for (Project project : projects) {
            Long poorDay = DateUtil.getDateMinus(project.getFinishTime(), DateUtil.parseDate(DateUtil.getDate()));
            if (poorDay < 0) {
                timeOutFIleProcessUserIds.add(project.getProjectId());
            }
            // 判断总任务是否完成
            if ("5".equals(project.getState())) {
                //任务完成 不做超时处理
                continue;
            }
            // 判断总任务是否超时
            if ("Y".equals(project.getIsTimeOut())) {
                // 任务超时 不重新做超时验证
                continue;
            }
            //判断任务是否超时->完成时间在当前时间之前的为未完成时间
//            if (fileProcessUser.getFinishTime().before(DateUtils.parseDate(DateUtils.getDate(), DateUtils.YYYY_MM_DD))) {
//                timeOutFIleProcessUserIds.add(fileProcessUser.getItemId());
//            }
            if (null != project.getRelFinishTime()) {
                if (DateUtil.getDateMinus(project.getFinishTime(), project.getRelFinishTime()) < 0) {
                    timeOutFIleProcessUserIds.add(project.getProjectId());
                }
            }
        }
        if (timeOutFIleProcessUserIds.size() > 0) {
            // 修改子任务超时状态
            projectMapper.updateTimeOutById(timeOutFIleProcessUserIds);
            // 修改我的待办工作超时状态
            fileProcessUserMapper.updateFileProcessUserTimeOutById(timeOutFIleProcessUserIds);
        }
    }
}
